// 防止头文件重复包含的宏定义
#ifndef __MY_SERVICE__
#define __MY_SERVICE__

#include "data.hpp"  // 数据管理相关头文件
#include "httplib.h" // HTTP服务器库头文件

// 声明外部全局变量，数据管理器实例
extern cloud::DataManager *_data;

namespace cloud
{
    // 定义Service类，提供HTTP服务
    class Service
    {
    private:
        int _server_port;             // 服务器监听端口
        std::string _server_ip;       // 服务器IP地址
        std::string _download_prefix; // 下载URL前缀
        httplib::Server _server;      // httplib服务器实例
    private:
        // 静态文件上传处理函数
        static void Upload(const httplib::Request &req, httplib::Response &rsp)
        {
            // 检查请求中是否包含命名为"file"的文件字段
            auto ret = req.has_file("file");
            if (ret == false)
            {
                rsp.status = 400; // 如果没有文件，返回400错误
                return;
            }

            // 获取上传文件的信息
            //  file.filename: 文件名, file.content: 文件内容
            const auto &file = req.get_file_value("file");

            // 获取备份目录路径
            std::string back_dir = Config::GetInstance()->GetBackDir();
            // 构建文件的完整保存路径
            std::string realpath = back_dir + FileUtil(file.filename).FileName();

            // 构建文件工具对象并写入内容
            FileUtil fu(realpath);
            fu.SetContent(file.content);

            // 创建备份信息对象并初始化
            BackupInfo info;
            info.NewBackupInfo(realpath);

            // 将备份信息插入数据管理器
            _data->Insert(info);
            return;
        }

        // 将时间戳转换为字符串格式
        static std::string TimetoStr(time_t t)
        {
            std::string tmp = std::ctime(&t);
            return tmp;
        }

        // 文件列表显示处理函数
        static void ListShow(const httplib::Request &req, httplib::Response &rsp)
        {
            // 获取所有备份文件信息
            std::vector<BackupInfo> arry;
            _data->GetAll(&arry);

            // 使用字符串流构建HTML页面
            std::stringstream ss;
            ss << "<html><head><title>Download</title></head>";
            ss << "<body><h1>Download</h1><table>";

            // 遍历所有备份文件，生成表格行
            for (auto &a : arry)
            {
                ss << "<tr>";
                // 从完整路径中提取文件名
                std::string filename = FileUtil(a.real_path).FileName();
                // 创建下载链接
                ss << "<td><a href='" << a.url << "'>" << filename << "</a></td>";
                // 显示文件修改时间
                ss << "<td align='right'>" << TimetoStr(a.mtime) << "</td>";
                // 显示文件大小（转换为KB）
                ss << "<td align='right'>" << a.fsize / 1024 << "k</td>";
                ss << "</tr>";
            }

            ss << "</table></body></html>";
            // 设置响应体和头部信息
            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
            return;
        }

        // 生成ETag（实体标签），用于缓存验证和断点续传
        static std::string GetETag(const BackupInfo &info)
        {
            // ETag格式: 文件名-文件大小-修改时间
            // etg :  filename-fsize-mtime
            FileUtil fu(info.real_path);
            std::string etag = fu.FileName();
            etag += "-";
            etag += std::to_string(info.fsize);
            etag += "-";
            etag += std::to_string(info.mtime);
            return etag;
        }

        // 文件下载处理函数
        static void Download(const httplib::Request &req, httplib::Response &rsp)
        {
            // 获取客户端请求的资源路径path   req.path
            // 根据请求路径获取对应的备份信息
            BackupInfo info;
            _data->GetOneByURL(req.path, &info);

            // 如果文件被压缩，需要先解压
            if (info.pack_flag == true)
            {
                FileUtil fu(info.pack_path);
                // 解压文件到备份目录
                fu.UnCompress(info.real_path);
                // 删除压缩包
                fu.Remove();
                // 更新备份信息（标记为未压缩状态）
                info.pack_flag = false;
                _data->Update(info);
            }

            // 检查是否需要断点续传
            bool retrans = false;
            std::string old_etag;
            if (req.has_header("If-Range"))
            {
                old_etag = req.get_header_value("If-Range");
                // 如果ETag匹配，则进行断点续传
                if (old_etag == GetETag(info))
                {
                    retrans = true;
                }
            }

            // 读取文件内容
            FileUtil fu(info.real_path);
            if (retrans == false)
            {
                // 普通下载，读取整个文件内容
                fu.GetContent(&rsp.body);
                // 设置响应头部
                rsp.set_header("Accept-Ranges", "bytes");                   // 支持请求范围
                rsp.set_header("ETag", GetETag(info));                      // 设置ETag
                rsp.set_header("Content-Type", "application/octet-stream"); // 二进制流类型
                rsp.status = 200;                                           // 成功状态码
            }
            else
            {
                // 断点续传，httplib会自动处理范围请求
                // httplib内部实现了对于区间请求也就是断点续传请求的处理
                // 只需要我们用户将文件所有数据读取到rsp.body中，它内部会自动根据请求
                // 区间，从body中取出指定区间数据进行响应
                // std::string  range = req.get_header_val("Range"); bytes=start-end
                fu.GetContent(&rsp.body);
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("ETag", GetETag(info));
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 206; // 部分内容状态码
            }
        }

    public:
        Service()
        {
            Config *config = Config::GetInstance();
            _server_port = config->GetServerPort();         // 获取端口
            _server_ip = config->GetServerIp();             // 获取IP
            _download_prefix = config->GetDownloadPrefix(); // 获取下载前缀
        }

        // 运行服务器模块
        bool RunModule()
        {
            // 注册路由和处理函数
            _server.Post("/upload", Upload);    // 文件上传路由
            _server.Get("/listshow", ListShow); // 列表显示路由
            _server.Get("/", ListShow);         // 跟路由也显示列表

            // 动态下载路由（使用正则表达式匹配）
            std::string download_url = _download_prefix + "(.*)";
            _server.Get(download_url, Download);

            // 启动服务器监听
            _server.listen(_server_ip.c_str(), _server_port);
            // while(1);
            return true;
        }
    };
}

#endif